<script setup>
import { reactive, ref, onMounted } from 'vue'
import { getListApi, getParentListApi, addMenuApi, editMenuApi, deleteMenuApi } from "@/api/menu"
import { resetForm, objCoppy, myConfrim } from '@/utils'

// 表格高度
const tableHeight = ref(0)
// 表格数据
const tableData = ref([])
// 弹窗属性
const dialog = reactive({
    title: '',
    visible: false,
    height: 260,
    width: 600
})

// 弹窗表单数据
const addModel = reactive({
    editType: '', // 0 新增 1 编辑
    menuId: '',
    parentId: '',
    title: '',
    code: '',
    name: '',
    path: '',
    url: '',
    type: '',
    icon: '',
    parentName: '',
    orderNum: ''
})
// 表单校验规则
const rules = {
    parentName: [
        {
            trigger: 'change',
            required: true,
            message: '请选择上级菜单'
        }
    ],
    title: [
        {
            trigger: 'blur',
            required: true,
            message: '请填写菜单名称'
        }
    ],
    code: [
        {
            trigger: 'blur',
            required: true,
            message: '请填写权限字段'
        }
    ],
    name: [
        {
            trigger: 'blur',
            required: true,
            message: '请填写路由名称'
        }
    ],
    path: [
        {
            trigger: 'blur',
            required: true,
            message: '请填写路由地址'
        }
    ],
    url: [
        {
            trigger: 'blur',
            required: true,
            message: '请填写组件路径'
        }
    ],
    type: [
        {
            trigger: 'blur',
            required: true,
            message: '请选择菜单类型'
        }
    ],
}
// 上级菜单弹框属性
const parentDialog = reactive({
    title: '选择上级菜单',
    visible: false,
    width: 300,
    height: 200
})
// 选择的上级节点
const selectNode = {
    menuId: '',
    title: ''
}
// 上级菜单树数据
const parentData = ref([])
const parentDefaultProps = {
    children: 'children',
    label: 'title'
}

// 获取表格数据
const getList = async () => {
    const res = await getListApi()
    tableData.value = res.data
}
getList()
const addRef = ref(null)
// 新增按钮
const addBtn = () => {
    dialog.title = '新增菜单'
    dialog.visible = true
    // 清空上一次的表单数据
    resetForm(addRef.value, addModel)
    // 设置编辑属性
    addModel.editType = '0'
}
// 编辑按钮
const editBtn = (row) => {
    dialog.title = '编辑菜单'
    dialog.visible = true
    // 清空上一次的表单数据
    resetForm(addRef.value, addModel)
    // 把要编辑的数据放入
    objCoppy(row, addModel)
    // 设置编辑属性
    addModel.editType = '1'
}
// 删除按钮
const deteleBtn = async (row) => {
    const confirm = await myConfrim('确定要删除该菜单吗?')
    if (confirm) {
        const res = await deleteMenuApi({ menuId: row.menuId })
        ElMessage({ type: 'success', message: res.msg })
        getList()
    }
}
// 弹窗确认
const onConfirm = async () => {
    // 表单验证
    await addRef.value.validate(async valid => {
        if (valid) {
            let res = null
            if (addModel.editType === '0') {
                res = await addMenuApi(addModel)
            } else if (addModel.editType === '1') {
                res = await editMenuApi(addModel)
            }
            ElMessage({ type: 'success', message: res.msg })
            getList()
            dialog.visible = false
        }
    })
}
// 弹窗取消
const onClose = () => dialog.visible = false
// 打开选择上级菜单的弹窗
const selectParent = async () => {
    // 查询上级菜单数据
    const res = await getParentListApi()
    parentData.value = res.data
    parentDialog.visible = true
}
// 选择上级菜单节点点击事件
const parentHandleNodeClick = (node) => {
    selectNode.menuId = node.menuId
    selectNode.title = node.title
}
// 选择上级弹框确认
const onParentConfirm = () => {
    addModel.parentId = selectNode.menuId
    addModel.parentName = selectNode.title
    parentDialog.visible = false
}
// 选择上级弹框取消
const onParentClose = () => {
    parentDialog.visible = false
}
const parentTree = ref(null)
// 上级菜单节点点击加号和减号事件
const openBtn = (data) => {
    data.open = !data.open
    parentTree.value.store.nodesMap[data.menuId].expanded = !data.open
}

onMounted(() => {
    tableHeight.value = window.innerHeight - 200
})
</script>

<template>
    <el-form size="small">
        <el-form-item>
            <el-button v-permission="['sys:sysMenuList:add']" type="primary" icon="Plus" @click="addBtn">新增</el-button>
        </el-form-item>
    </el-form>
    <!-- default-expand-all 默认展开全部 -->
    <el-table :height="tableHeight" :data="tableData" style="width: 100%;" row-key="menuId" border lazy
        :tree-props="{ children: 'children', hasChildren: 'hasChildren' }">
        <el-table-column prop="title" label="菜单名称"></el-table-column>
        <el-table-column prop="type" label="菜单类型">
            <template #default="scope">
                <el-tag v-if="scope.row.type === '0'">目录</el-tag>
                <el-tag v-if="scope.row.type === '1'" type="success">菜单</el-tag>
                <el-tag v-if="scope.row.type === '2'" type="danger">按钮</el-tag>
            </template>
        </el-table-column>
        <el-table-column prop="icon" label="菜单图标">
            <template #default="scope">
                <svg-icon :name="scope.row.icon" />
            </template>
        </el-table-column>
        <el-table-column prop="name" label="路由名称"></el-table-column>
        <el-table-column prop="path" label="路由地址"></el-table-column>
        <el-table-column prop="url" label="路由路径"></el-table-column>
        <el-table-column prop="code" label="权限字段"></el-table-column>
        <el-table-column prop="orderNum" label="菜单序号"></el-table-column>
        <el-table-column v-permission="['sys:sysMenuList:edit', 'sys:sysMenuList:delete']" fixed="right" label="操作"
            width="160" align="center">
            <template #default="scope">
                <div flex>
                    <el-button type="primary" size="small" icon="Edit" @click="editBtn(scope.row)">编辑</el-button>
                    <el-button type="danger" size="small" icon="Delete" @click="deteleBtn(scope.row)">删除</el-button>
                </div>
            </template>
        </el-table-column>
    </el-table>
    <!-- 编辑/新增弹窗 -->
    <el-dialog v-model="dialog.visible" :width="dialog.width" :close-on-click-modal="false">
        <template #header>
            <h1>{{ dialog.title }}</h1>
        </template>
        <div :style="{ height: dialog.height + 'px' }">
            <el-form :model="addModel" ref="addRef" :rules="rules">
                <el-row>
                    <el-col :span="24" :offset="0">
                        <el-form-item prop="type" label="菜单类型">
                            <el-radio-group v-model="addModel.type">
                                <el-radio :label="'0'">目录</el-radio>
                                <el-radio :label="'1'">菜单</el-radio>
                                <el-radio :label="'2'">按钮</el-radio>
                            </el-radio-group>
                        </el-form-item>
                    </el-col>
                </el-row>

                <el-row>
                    <el-col :span="12" :offset="0">
                        <el-form-item prop="parentName" label="上级菜单">
                            <el-input @click.native="selectParent" v-model="addModel.parentName"></el-input>
                        </el-form-item>
                    </el-col>
                    <el-col :span="12" :offset="0">
                        <el-form-item prop="title" label="菜单名称">
                            <el-input v-model="addModel.title"></el-input>
                        </el-form-item>
                    </el-col>
                </el-row>

                <el-row>
                    <el-col v-if="addModel.type != '2'" :span="12" :offset="0">
                        <el-form-item label="菜单图标">
                            <el-input v-model="addModel.icon"></el-input>
                        </el-form-item>
                    </el-col>
                    <el-col v-if="addModel.type !== '2'" :span="12" :offset="0">
                        <el-form-item prop="name" label="路由名称">
                            <el-input v-model="addModel.name"></el-input>
                        </el-form-item>
                    </el-col>
                </el-row>

                <el-row>
                    <el-col :span="12" :offset="0">
                        <el-form-item label="菜单序号">
                            <el-input v-model="addModel.orderNum"></el-input>
                        </el-form-item>
                    </el-col>
                    <el-col :span="12" :offset="0">
                        <el-form-item prop="code" label="权限字段">
                            <el-input v-model="addModel.code"></el-input>
                        </el-form-item>
                    </el-col>
                </el-row>

                <el-row>
                    <el-col v-if="addModel.type === '1'" :span="12" :offset="0">
                        <el-form-item prop="url" label="路由路径">
                            <el-input v-model="addModel.url"></el-input>
                        </el-form-item>
                    </el-col>
                    <el-col v-if="addModel.type !== '2'" :span="12" :offset="0">
                        <el-form-item prop="path" label="路由地址">
                            <el-input v-model="addModel.path"></el-input>
                        </el-form-item>
                    </el-col>
                </el-row>

            </el-form>
        </div>
        <template #footer>
            <span class="dialog-footer">
                <el-button @click="onClose">取消</el-button>
                <el-button type="primary" @click="onConfirm">确定</el-button>
            </span>
        </template>
    </el-dialog>

    <!-- 上级菜单弹框 -->
    <el-dialog v-model="parentDialog.visible" :width="parentDialog.width" :close-on-click-modal="false">
        <template #header>
            <h1>{{ parentDialog.title }}</h1>
        </template>
        <div :style="{ height: parentDialog.height + 'px' }" style="overflow-y: auto;">
            <el-tree ref="parentTree" :data="parentData" :props="parentDefaultProps" @node-click="parentHandleNodeClick"
                empty-text="暂无数据" :show-checkbox="false" :highlight-current="true" :expand-on-click-node="false"
                node-key="menuId" default-expand-all>
                <template #default="{ node, data }">
                    <!-- 如果没有下级显示文档图标 -->
                    <span v-if="data.children.length === 0">
                        <i style="margin-left: 3px;" class="el-icon-document"></i>
                    </span>
                    <!-- 有下级,判断是否展开 -->
                    <span v-else @click.stop="openBtn(data)">
                        <i v-if="data.open" style="margin-left: 3px;" class="el-icon-plus"></i>
                        <i v-else style="margin-left: 3px;" class="el-icon-minus"></i>
                    </span>
                    <span style="margin-left: 3px;">{{ node.label }}</span>
                </template>
            </el-tree>
        </div>
        <template #footer>
            <span class="dialog-footer">
                <el-button @click="onParentClose">取消</el-button>
                <el-button type="primary" @click="onParentConfirm">确定</el-button>
            </span>
        </template>
    </el-dialog>
</template>


<style scoped>
:deep(.el-tree .el-tree-node) {
    position: relative;
    padding-left: 10px;
}

:deep(.el-tree .el-tree-node__children) {
    padding-left: 20px;
}

:deep(.el-tree .el-tree-node :last-child::before) {
    height: 40px;
}

:deep(.el-tree .el-tree>.el-tree-node::before) {
    border-left: none;
}

:deep(.el-tree .el-tree>.el-tree-node::after) {
    border-left: none;
}

:deep(.el-tree .el-tree-node::before),
:deep(.el-tree .el-tree-node::after) {
    content: "";
    left: -4px;
    position: absolute;
    right: auto;
    border-width: 1px;
}

:deep(.el-tree .tree:first-child .el-tree-node::before) {
    border-left: none;
}

:deep(.el-tree .el-tree-node::before) {
    border-left: 1px dotted #d9d9d9;
    bottom: 0px;
    height: 100%;
    top: -25px;
    width: 1px;
}

:deep(.el-tree .el-tree-node::after) {
    border-top: 1px dotted #d9d9d9;
    height: 20px;
    top: 14px;
    width: 24px;
}

:deep(.el-tree .el-tree-node__expand-icon.is-leaf) {
    width: 8px;
}

:deep(.el-tree .el-tree-node__content>.el-tree-node__expand-icon) {
    display: none;
}

:deep(.el-tree .el-tree-node__content) {
    line-height: 30px;
    height: 30px;
    padding-left: 10px !important;
}

:deep(.el-tree .el-tree>div::before) {
    display: none;
}

:deep(.el-tree .el-tree>div::after) {
    display: none;
}
</style>